﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using StarsAdmin.Core.App;
using StarsAdmin.Core.Cache;
using StarsAdmin.Core.Consts;
using StarsAdmin.Core.Helpers;
using StarsAdmin.Core.Models;
using System.Security.Claims;

namespace StarsAdmin.Web.Core.Filter
{
    /// <summary>
    /// 鉴权过滤器
    /// </summary>
    public class AuthenticationFilter : IAsyncAuthorizationFilter
    {
        private readonly ICacheService _cache;

        public AuthenticationFilter()
        {
            _cache = AppHelper.GetService<ICacheService>() ?? throw new ArgumentNullException();
        }

        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            // 如果有 AllowAnonymous 标签，则跳过
            if (context.Filters.Any(p => p is IAllowAnonymousFilter))
            {
                return;
            }
            var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
            // 如果是请求登录，则跳过
            if (controllerActionDescriptor?.ActionName == "Login")
            {
                return;
            }
            // 获取Token
            var authHeader = context.HttpContext.Request.Headers["Authorization"].ToString().Split(" ");
            if (authHeader.Length != 2 || !authHeader[0].Equals("Bearer", StringComparison.OrdinalIgnoreCase))
            {
                Set401Result(context, "没有找到Token令牌，请登录");
                return;
            }
            var token = authHeader[1];
            // 验证Token
            var flag = JwtHelper.ValidateAccessToken(token, out ClaimsPrincipal? principal, out _);
            if (!flag && principal == null)
            {
                Set401Result(context, "无效的Token令牌，请重新登录");
                return;
            }
            // 验证当前用户是否存在
            var userId = JwtHelper.GetUserId(token);
            if (userId == default)
            {
                Set401Result(context, "无效的Token令牌，请重新登录");
                return;
            }
            // 验证token版本是否正确
            var version = JwtHelper.GetTokenVersion(token);
            var cacheVersion = await _cache.GetAsync<string>(userId, CacheKeyConst.TokenVersionKey);
            if (version != cacheVersion)
            {
                Set401Result(context, "Token令牌已过期，请重新登录");
                return;
            }
        }

        /// <summary>
        ///设置返回值
        /// </summary>
        /// <param name="context"></param>
        /// <param name="statusCode"></param>
        /// <param name="message"></param>
        public void Set401Result(AuthorizationFilterContext context, string message)
        {
            var result = ResultModel<string>.Error(message, 401);
            context.HttpContext.Response.StatusCode = 401;
            context.Result = new JsonResult(result);
            return;
        }
    }
}